<?php

namespace app\common\library;
use app\common\library\Unit;
use app\common\model\Attachment;
use think\Env;

class EsignServer
{
    protected $appid;
    protected $secret;
    protected $stoken;
    protected $orgid;
    protected $seal;
    protected $option;

    public function __construct($option){
        $this->appid = Env::get('esign.appid');
        $this->secret = Env::get('esign.secret');
        $this->orgid = Env::get('esign.orgid');
        $this->seal = Env::get('esign.seal');
        $this->option = $option;
    }
    public function createAccountID($arr){
        $this->getoauth();//获取鉴权Token
        //请求地址
        $API_Host="https://openapi.esign.cn";
        //创建账户
        $Url=$API_Host."/v1/organizations/createByThirdPartyUserId";
        $data = json_encode($arr);
        $until = new Unit();
        $return_content = $until->doPost($Url,$data,$this->appid,$this->stoken);
        $result = (array)json_decode($return_content,true);
        $url=$API_Host."/v1/signAuth/".$result['data']['orgId'];
        $res=$until->doPost($url,"",$this->appid,$this->stoken);
        return ['result'=>$result,"res"=>$res];
    }
    public function addEsign()
    {
        $this->getoauth();
        //请求地址
        $API_Host = "https://openapi.esign.cn";
        //创建个人账户
        $Url = $API_Host . "/v1/accounts/createByThirdPartyUserId";
        //手机号签署链接会通知到手机号和邮箱 建议使用真实信息创建账号，避免后续因账号问题导致的错误
//            dump($userid);
        $userid= 'B' . date("YmdHis", time()) . mt_rand(1000, 9000);
        $arr = array(
            'thirdPartyUserId' => $userid,
            'name' =>$this->option['name'],
            'idNumber' => $this->option['card_no'],
            'idType' => $this->option['card_type'],
            'mobile' => $this->option['phone'],
        );
        $config=config('sealxyp');
        $doc_type=$this->option['doc_type'];
        $sealConfig=$config[$doc_type]?$config[$doc_type]:"";
        setLog(__METHOD__,"合同类型".$doc_type);
        setLog(__METHOD__,"印章配置".json_encode($sealConfig,256));
        if(!$sealConfig){
            setLog(__METHOD__,"没有找到对应的合同类型".$doc_type."的印章配置");
        }

        $data = json_encode($arr);
        $until = new Unit();
        $return_content = $until->doPost($Url, $data, $this->appid, $this->stoken);
        //var_dump("创建个人账户结果集：".$return_content);
        $result = (array)json_decode($return_content, true);
//            halt($result);
        if ($result['code'] != 0) {
            setLog(__METHOD__,$result);
            return false;
        }
        $data2 = $result['data'];
        $accountID = $data2['accountId'];
//            dump($accountID);
        if (!$accountID) {
            setLog(__METHOD__,"签名创建失败");
            return false;
        }
        //设置静默签署
        $addSign = $API_Host . "/v1/signAuth/{accountId}";
        $addSign = str_replace('{accountId}', $accountID, $addSign);
        $arr = array('accountId' => $accountID);
        $data = json_encode($arr);
        $until = new Unit();
        $until->doPost($addSign, $data, $this->appid, $this->stoken);
        $filePath=".".$this->option['doc_file'];
        $pathInfo=pathinfo($filePath);
        //文件直传创建带签署文件
        $upsloadUrl = $API_Host . "/v1/files/getUploadUrl";
        $creataFlow = $API_Host . "/v1/signflows";
        $title=$this->option['doc_name'];
        $flowid = $this->creatFlow($this->appid, $this->stoken, $creataFlow, $title);
        if (!$flowid) {
            setLog(__METHOD__,"创建签署流程失败");
            return false;
        }
        $data2 = $this->getuploadUrl($this->appid, $this->stoken, $upsloadUrl, $filePath);
        //文件fileId
        $fileId = $data2['fileId'];
        //文件直传地址
        $uploadUrls = $data2['uploadUrl'];
        //上传文件
        $this->upLoadFile($uploadUrls, $filePath);
        //流程文档添加
        $addaDocumnet = $API_Host . "/v1/signflows/{flowId}/documents";
        $addPlatformSign = $API_Host . "/v1/signflows/{flowId}/signfields/autoSign";
        $this->addDocumnet($this->appid, $this->stoken, $addaDocumnet, $flowid, $fileId);
        //印章添加
        setLog(__METHOD__,$sealConfig);
        list($page,$posx,$posy)=$sealConfig['left'];
        // $page =  4;//第1页盖章

        // $posx = 150;//印章X轴
        // $posy = 150;//印章Y轴
        $red = $this->addPlatformSign($this->appid, $this->stoken, $addPlatformSign, $flowid, $fileId,$page,$posx,$posy);
        setLog(__METHOD__,"添加平台印章");
        setLog(__METHOD__,json_encode($red,256));
        $addHandSign = $API_Host . "/v1/signflows/{flowId}/signfields/handSign";
        list($pages,$posxs,$posys)=$sealConfig['right'];
        // $pages = 4;
        // $posxs = 460;
        // $posys = 150;//印章Y轴
        $ewd1 = $this->addHandSign($this->appid, $this->stoken, $addHandSign, $flowid, $fileId, $accountID, $pages, $posxs, $posys);
        setLog(__METHOD__,"个人签署");
        setLog(__METHOD__,$ewd1);
        //流程开启，开启成功后将会收到短信通知!
        $startSign = $API_Host . "/v1/signflows/{flowId}/start";
        $esd = $this->startSign($this->appid, $this->stoken, $startSign, $flowid);
        setLog(__METHOD__,'开启流程');
        setLog(__METHOD__,$esd);
        //获取签署地址
        $downloadDocument = $API_Host . "/v1/signflows/{flowId}/executeUrl";
        $downloadDocument = str_replace('{flowId}', $flowid, $downloadDocument);
        $arr = array('flowId' => $flowid, 'accountId' => $accountID);
        $data = json_encode($arr);
        $return_content = $until->doGetWithToken($downloadDocument . '?accountId=' . $accountID, $data, $this->appid, $this->stoken);
        $result = (array)json_decode($return_content, true);
        $data = $result['data'];
        $url = $data['url'];
        setLog(__METHOD__,"签署地址".$url);
        //删除本地文件和素材库
        $attachment=Attachment::get(['url'=>$this->option['doc_file'],"storage"=>"local"]);
        $attachment->delete();
        @unlink(".".$this->option['doc_file']);
        return ['follow_id'=>$flowid,"sign_url"=>$url,'account_id'=>$accountID];
    }
    public function delesign()
    {//删除个人账号并撤销签署流程
        $this->getoauth();//获取鉴权Token
        $oid = request()->param('id');//课程订单id
        //删除个人账号
        $API_Host = "https://openapi.esign.cn";
        $startSign = $API_Host . "/v1/accounts/{accountId}";
        $this->startSigns($this->appid, $this->stoken, $startSign, $name['accountid']);
        //撤销签署流程
        $startSign = $API_Host . "/v1/signflows/{flowId}/revoke";
        $this->startSign($this->appid, $this->stoken, $startSign, $name['flowid']);
        db('eqianbao')->where('oid', $oid)->delete();
        //更新课程订单
        db('order')->where('id', $oid)->update(['esign' => '无', 'esign_type' => '无']);
        return json(['status' => 1, 'message' => '删除成功']);
    }

    //流程开启
    public function startSign($appId, $stoken, $startSign, $flowid)
    {
        $startSign = str_replace('{flowId}', $flowid, $startSign);
        $until = new Unit();
        $return_content = $until->sendHttpPUTCommon($startSign, [], $appId, $stoken);
        $result = (array)json_decode($return_content);
        return $result;
    }

    //删除个人账号
    public function startSigns($appId, $stoken, $startSign, $accountId)
    {
        $startSign = str_replace('{accountId}', $accountId, $startSign);
        $until = new Unit;
        $return_content = $until->sendHttpPUTCommons($startSign, [], $appId, $stoken);
        $result = (array)json_decode($return_content);
        return $result;
    }

    //印章添加
    public function addPlatformSign($appId, $stoken, $addPlatformSign, $flowid, $fileId,$page,$posx,$posy)
    {
        $addPlatformSign = str_replace('{flowId}', $flowid, $addPlatformSign);

        $orgid=$this->orgid;
        $arr=array('signfields'=>array(array('fileId'=>$fileId,'authorizedAccountId'=>$orgid,'sealId'=>$this->seal,'signType'=>'1','posBean'=>array('posPage'=>$page,'posX'=>$posx,'posY'=>$posy,))));
        $data=json_encode($arr);
        $until = new Unit;
        $return_content = $until->doPost($addPlatformSign, $data, $appId, $stoken);
        $res = (array)json_decode($return_content);
        return $res;
    }

    //手动签字
    public function addHandSign($appId, $stoken, $addHandSign, $flowid, $fileId, $accountId, $pages, $posxs, $posys)
    {
        $addHandSign = str_replace('{flowId}', $flowid, $addHandSign);
        $arr = array('signfields' => array(array('order' => '1', 'fileId' => $fileId, 'signerAccountId' => $accountId, 'signType' => '1', 'posBean' => array('posPage' => $pages, 'posX' => $posxs, 'posY' => $posys,))));
        $data = json_encode($arr);
        $until = new Unit;
        $return_content = $until->doPost($addHandSign, $data, $appId, $stoken);
        $res = (array)json_decode($return_content);
        return $res;
    }
    //企业签
    public function addHandSignOrg($appId, $stoken, $addHandSign, $flowid, $signDataOrg)
    {
        $addHandSign = str_replace('{flowId}', $flowid, $addHandSign);
        $arr = array(
            'signfields' => array(
                $signDataOrg
            )
        );
        $data = json_encode($arr);
        $until = new Unit;
        $return_content = $until->doPost($addHandSign, $data, $appId, $stoken);
        $res = (array)json_decode($return_content);
        return $res;
    }
    //流程文档添加
    public function addDocumnet($appId, $stoken, $addaDocumnet, $flowid, $fileId)
    {
        $addaDocumnet = str_replace('{flowId}', $flowid, $addaDocumnet);
        $arr = array('docs' => array(array('fileId' => $fileId)));
        $data = json_encode($arr);
        $until = new Unit;
        $return_content = $until->doPost($addaDocumnet, $data, $appId, $stoken);
        //var_dump($return_content);
        $result = json_decode($return_content);
        return $result;
    }

    public function upLoadFile($uploadUrls, $filePath)
    {
        //文件内容
        $fileContent = file_get_contents($filePath);
        $contentMd5 = $this->getContentBase64Md5($filePath);
        $Until = new Unit;
        $Until->sendHttpPUT($uploadUrls, $contentMd5, $fileContent);
    }

    //文件直传创建待签署文件
    public function getuploadUrl($appId, $stoken, $upsloadUrl, $filePath)
    {
        $fileName = basename($filePath);
        $fileSize = filesize($filePath);
        $contentType = 'application/pdf';
        $contentMd5 = $this->getContentBase64Md5($filePath);
        $arr = array('fileName' => $fileName, 'fileSize' => $fileSize, 'contentType' => $contentType, 'contentMd5' => $contentMd5);
        $data = json_encode($arr);
        $until = new Unit;
        $return_content = $until->doPost($upsloadUrl, $data, $appId, $stoken);
        //var_dump("获取文件fileId以及文件上传地址：".$return_content);
        $result = (array)json_decode($return_content, true);
        if (!isset($result['data'])) {
            $this->getoauth();
            $this->getuploadUrl($appId, $stoken, $upsloadUrl, $filePath);
        }
        $data2 = $result['data'];
        return $data2;
    }

    /**
     * 获取文件的Content-MD5
     * 原理：1.先计算MD5加密的二进制数组（128位）
     * 2.再对这个二进制进行base64编码（而不是对32位字符串编码）
     */
    private function getContentBase64Md5($filePath)
    {
        //获取文件MD5的128位二进制数组
        $md5file = md5_file($filePath, true);
        //计算文件的Content-MD5
        $contentBase64Md5 = base64_encode($md5file);
        return $contentBase64Md5;
    }

    //创建签署流程 短信签
    public function creatFlow($appId, $stoken, $upsloadUrl, $title)
    {
        //通知方式，逗号分割，1-短信，2-邮件
        $aar = array('autoArchive' => true, 'businessScene' => $title, 'configInfo' => array('noticeType' => '1'));
        $data = json_encode($aar);
        $until = new Unit;
        $return_content = $until->doPost($upsloadUrl, $data, $appId, $stoken);
        //var_dump("创建签署流程：".$return_content);
        $result = (array)json_decode($return_content);
        if (!isset($result['data'])) {
            $this->getoauth();
            $this->creatFlow($appId, $stoken, $upsloadUrl, $title);
        }
        $data2 = $result['data'];
        //flowId作为$data2的第一个关键字
        $flowId = $data2->flowId;
        return $flowId;
    }

    //创建签署流程 邮件签
    public function creatFlows($appId, $stoken, $upsloadUrl, $title)
    {
        //通知方式，逗号分割，1-短信，2-邮件
        $aar = array('autoArchive' => true, 'businessScene' => $title, 'configInfo' => array('noticeType' => '2'));
        $data = json_encode($aar);
        $until = new Unit;
        $return_content = $until->doPost($upsloadUrl, $data, $appId, $stoken);
        //var_dump("创建签署流程：".$return_content);
        $result = (array)json_decode($return_content);
        if (!isset($result['data'])) {
            $this->getoauth();
            $this->creatFlows($appId, $stoken, $upsloadUrl, $title);
        }
        $data2 = $result['data'];
        //flowId作为$data2的第一个关键字
        $flowId = $data2->flowId;
        return $flowId;
    }

    //流程归档
    public function archiveSign($appId, $stoken, $archiveSign, $flowid)
    {
        $archiveSign = str_replace('{flowId}', $flowid, $archiveSign);
        $until = new Unit;
        $data = [];
        $return_content = $until->sendHttpPUTCommon($archiveSign, $data, $appId, $stoken);
        $result = (array)json_decode($return_content);
        return $result;
    }

    //流程下载
    public function downloadDocument($appId, $stoken, $downloadDocument, $flowid)
    {
        $downloadDocument = str_replace('{flowId}', $flowid, $downloadDocument);
        $until = new Unit;
        $data = [];
        $return_content = $until->doGetWithToken($downloadDocument, $data, $appId, $stoken);
        $result = (array)json_decode($return_content, true);
        return $result;
    }

    public function getCompaneyId($tid, $accountid)
    {
        $API_Host = "https://openapi.esign.cn";
        //创建账户
        $Url = $API_Host . "/v1/organizations/createByThirdPartyUserId";
        $arr = array('thirdPartyUserId' => $tid, 'creator' => $accountid, 'name' => '北京京师万学教育科技有限公司', 'idType' => 'CRED_ORG_USCC', 'idNumber' => '91110108597749195E', 'orgLegalIdNumber' => '110108198502281411', 'orgLegalName' => '刘杉');
        $data = json_encode($arr);
        $until = new Unit;
        $oauth = db('eqianbao_oauth')->where('id', 1)->find();
        $return_content = $until->doPost($Url, $data, $this->appid, $this->stoken);
//        dump("创建机构账户结果集：" . $return_content);
        $result = (array)json_decode($return_content, true);
//        dump($result);
    }

    public function getoauth()
    {
        //获取鉴权Token
        $appid=Env::get('esign.appid');
        $secret=Env::get('esign.secret');
//        $oauth=config('eqb');
//        dump($oauth);
        $API_Host = "https://openapi.esign.cn";//请求地址
        $getToken = $API_Host . "/v1/oauth2/access_token";//获取鉴权Token
        $grantType = "client_credentials";
        $arr = array("appId" => $appid, "secret" => $secret, "grantType" => $grantType);
        $data = json_encode($arr);
        $until = new Unit();
        $getToken = $getToken . "?appId={$appid}&secret={$secret}&grantType=client_credentials";
        $return_content = $until->doGet($getToken, $data);
//        dump($return_content);
        //var_dump("获取鉴权Token:".$return_content);
        $result = (array)json_decode($return_content, true);
//        halt($result);
        if (!isset($result['data'])) {
            $this->getoauth();
        }
        $data2 = $result['data'];
        $stokren = $data2['token'];//获取到的鉴权token
//        session('stoken',$data2['token']);
        //保存鉴权Token
        $this->stoken=$stokren;
    }

    public function checkVerify($flowid)
    {
//        if(){}
        $this->getoauth();
        $API_Host="https://openapi.esign.cn";
        $downloadDocument=$API_Host."/v1/signflows/{flowId}";
        $downloadDocument = str_replace('{flowId}',$flowid,$downloadDocument);
        $until=new Unit();
        $data = [];
        $return_content=$until->doGetWithToken($downloadDocument,$data,$this->appid,$this->stoken);
        $result=(array)json_decode($return_content,true);
        if(!isset($result['data'])){
            return "签署中";
        }
        $data=$result['data'];
        $flowDesc=$data['flowDesc'];//签署状态
        return $flowDesc;
    }

}